《Android开源库》 Retrofit & WebService

1. 前言

最近工作中需要使用到WebService接口,个人比较喜欢Restful的接口风格,对WebService不是很了解。

Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的独立的通讯技术。是:通过SOAP在Web上提供的软件服务,使用WSDL文件进行说明,并通过UDDI进行注册。

而对于我们移动开发人员而言,它就是一种数据交互的通道。我们需要了解他的请求结构体和响应结构体。

2. WebService调试工具SoapUI

SoapUI是一个开源测试工具,通过soap/http来检查、调用、实现Web Service的功能/负载/符合性测试。该工具既可作为一个单独的测试软件使用,也可利用插件集成到Eclipse,maven2.X,Netbeans 和intellij中使用。SoapUI Pro是SoapUI的商业非开源版本,实现的功能较开源的SoapUI更多。
(找不到资源的可以在文章下方留言)
这里写图片描述

3. 接口分析(以getMobileCodeInfo为例)

http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl 为测试例子

这里写图片描述
这里写图片描述

从上面两个图可以看到我们得请求体和响应体的结构和内容,以XML格式作为数据交互的结构类型。

4. 程序设计

4.1 添加依赖

1
2
3
4
5
6
7
8
9
implementation 'com.squareup.okhttp3:okhttp:3.8.0'
implementation 'com.parkingwang:okhttp3-loginterceptor:0.5'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
implementation('com.squareup.retrofit2:converter-simplexml:2.3.0') {
exclude module: 'stax'
exclude module: 'stax-api'
exclude module: 'xpp3'
}

4.2 请求体设计

从请求体XML结构而言

1
2
3
4
5
6
7
8
9
10
11
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:web="http://WebXml.com.cn/">
<soap:Header/>
<soap:Body>
<web:getMobileCodeInfo>
<!--Optional:-->

<!--Optional:-->
<web:mobileCode>18507152743</web:mobileCode>
</web:getMobileCodeInfo>
</soap:Body>
</soap:Envelope>

最外层soap:Envelope
其次soap:Body
最后web:getMobileCodeInfo,而web:getMobileCodeInfo中有一个mobileCode我们可以用变量表示,所以创建如下三个类:
MobileCodeRequestEnvelope.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Root(name = "soap:Envelope")
@NamespaceList({
@Namespace(prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
@Namespace(prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
@Namespace(prefix = "soap", reference = "http://www.w3.org/2003/05/soap-envelope")
})
public class MobileCodeRequestEnvelope {

@Element(name = "soap:Body", required = false)
private MobileCodeRequestBody body;

public MobileCodeRequestBody getBody() {
return body;
}

public void setBody(MobileCodeRequestBody body) {
this.body = body;
}
}

MobileCodeRequestBody.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Root(name = "soap:Body", strict = false)
public class MobileCodeRequestBody {
@Element(name = "getMobileCodeInfo", required = false)
private MobileCodeRequestData mMobileCodeRequestData;

public MobileCodeRequestData getMobileCodeRequestData() {
return mMobileCodeRequestData;
}

public void setMobileCodeRequestData(
MobileCodeRequestData mobileCodeRequestData) {
mMobileCodeRequestData = mobileCodeRequestData;
}
}

MobileCodeRequestData.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Root(name = "getMobileCodeInfo", strict = false)
@Namespace(reference = "http://WebXml.com.cn/")
public class MobileCodeRequestData {
@Element(name = "mobileCode", required = false)
private String mobileCode;

public String getMobileCode() {
return mobileCode;
}

public void setMobileCode(String mobileCode) {
this.mobileCode = mobileCode;
}
}

4.3 响应体设计

从响应体XML而言

1
2
3
4
5
6
7
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<getMobileCodeInfoResponse xmlns="http://WebXml.com.cn/">
<getMobileCodeInfoResult>18507152743:湖北 武汉 湖北联通GSM卡</getMobileCodeInfoResult>
</getMobileCodeInfoResponse>
</soap:Body>
</soap:Envelope>

最外层soap:Envelope
其次soap:Body
然后getMobileCodeInfoResponse,最后getMobileCodeInfoResult,我们可以用变量表示,所以创建如下三个类:

MobileCodeResponseEnvelope.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Root(name = "soap:Envelope")
@NamespaceList({
@Namespace( prefix = "xsi", reference = "http://www.w3.org/2001/XMLSchema-instance"),
@Namespace( prefix = "xsd", reference = "http://www.w3.org/2001/XMLSchema"),
@Namespace( prefix = "soap", reference = "http://www.w3.org/2003/05/soap-envelope")
})
public class MobileCodeResponseEnvelope {
@Element(name = "Body", required = false)
private MobileCodeResponseBody mMobildCodeResponseBody;

public MobileCodeResponseBody getMobildCodeResponseBody() {
return mMobildCodeResponseBody;
}

public void setMobildCodeResponseBody(
MobileCodeResponseBody mobildCodeResponseBody) {
mMobildCodeResponseBody = mobildCodeResponseBody;
}
}

MobileCodeResponseBody.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Root(name = "Body")
public class MobileCodeResponseBody {
public MobileCodeResponseInfo getMobileCodeResponseInfo() {
return mMobileCodeResponseInfo;
}

public void setMobileCodeResponseInfo(
MobileCodeResponseInfo mobileCodeResponseInfo) {
mMobileCodeResponseInfo = mobileCodeResponseInfo;
}

@Element(name = "getMobileCodeInfoResponse", required = false)
private MobileCodeResponseInfo mMobileCodeResponseInfo;
}

MobileCodeResponseInfo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Root(name = "getMobileCodeInfoResponse",strict = false)
public class MobileCodeResponseInfo {

public String getMobileCodeResult() {
return MobileCodeResult;
}

public void setMobileCodeResult(String mobileCodeResult) {
MobileCodeResult = mobileCodeResult;
}

@Element(name = "getMobileCodeInfoResult", required = false)
private String MobileCodeResult;
}

4.4 接口设计

1
2
3
4
5
6
7
8
9
public interface mobileCodeApi {
@Headers({
"Content-Type: text/xml",
"Accept-Charset: utf-8"
})
@POST("MobileCodeWS.asmx")
Call<MobileCodeResponseEnvelope> getMobileCodeInfo(
@Body MobileCodeRequestEnvelope requestEnvelope);
}

4.5 Retrofit创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class Retrofitance {
private static Strategy strategy = new AnnotationStrategy();
private static Serializer serializer = new Persister(strategy);

private static OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();

private static Retrofit.Builder retrofitBuilder = new Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create(serializer))
.baseUrl(Constant.BASE_URL);


public static <T> T createMobileCodeService(Class<T> serviceClass) {
okHttpClient.interceptors().add(new Interceptor() {
@Override
public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();

Request.Builder requestBuilder = original.newBuilder()
.header("Content-Type", "text/xml;charset=UTF-8")
.method(original.method(), original.body());

Request request = requestBuilder.build();
return chain.proceed(request);
}
});

OkHttpClient client = okHttpClient.connectTimeout(1, TimeUnit.MINUTES)
.addInterceptor(new LogInterceptor())
.writeTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.build();
Retrofit retrofit = retrofitBuilder.client(client).build();
return retrofit.create(serviceClass);
}
}

4.6 请求数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
mobileCodeApi apiService = Retrofitance.createMobileCodeService(mobileCodeApi.class);
MobileCodeRequestEnvelope requestEnvelope = new MobileCodeRequestEnvelope();
MobileCodeRequestBody requestBody = new MobileCodeRequestBody();
MobileCodeRequestData requestData = new MobileCodeRequestData();

requestData.setMobileCode("18507152743");
requestBody.setMobileCodeRequestData(requestData);
requestEnvelope.setBody(requestBody);

Call<MobileCodeResponseEnvelope> call = apiService.getMobileCodeInfo(requestEnvelope);
call.enqueue(new Callback<MobileCodeResponseEnvelope>() {
@Override
public void onResponse(Call<MobileCodeResponseEnvelope> call,
Response<MobileCodeResponseEnvelope> response) {
MobileCodeResponseEnvelope mobileCodeResponseEnvelope = response.body();
if (mobileCodeResponseEnvelope != null) {
Toast.makeText(MainActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
String result =
mobileCodeResponseEnvelope.getMobildCodeResponseBody()
.getMobileCodeResponseInfo().getMobileCodeResult();
mTvMobileResult.setText(result);
System.err.println("yidong -- result = " + result);
}
}

@Override
public void onFailure(Call<MobileCodeResponseEnvelope> call, Throwable t) {
System.err.println("yidong -- onFailure");
Toast.makeText(MainActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
}
});

4.7 效果

这里写图片描述

5. 源码地址

RetrofitWebService

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×